#ifndef RP2WINDOWAPPLICATION_H
#define RP2WINDOWAPPLICATION_H

#include "Rp2Application.h"

namespace Rp2
{

class Renderer;

class WindowApplication : public Application
{
// Root class for window application
public:
	WindowApplication(const tCHAR* m_acWindowTitle, int iXPosition,
		int iYPosition, int iWidth, int iHeight);
	virtual ~WindowApplication();

	static int Run();

	virtual int Main();

	virtual void InitRenderStates();

	// member access
    const tCHAR* GetWindowTitle () const;
    int GetXPosition () const;
    int GetYPosition () const;
	int GetWidth() const;
	int GetHeight() const;

	// events call back functions.
	virtual bool OnInitialize();
	virtual void OnTerminate();
	virtual void OnDisplay();
	virtual void OnIdle();
	virtual bool OnKeyDown(unsigned char ucKey, int iXPos, int iYPos);
	virtual bool OnKeyUp(unsigned char ucKey, int iXPos, int iYPos);
	virtual bool OnSpecialKeyDown(int iKey, int iXPos, int iYPos);
	virtual bool OnSpecialKeyUp(int iKey, int iXPos, int iYPos);
	virtual bool OnMouseClick(int iButton, int iState, int iX, int iY,
		unsigned int uiModifiers);
	virtual bool OnMotion(int iButton, int iX, int iY, unsigned int uiModifiers);
	virtual bool OnPassiveMotion(int iX, int iY);
	virtual void OnResize(int iWidth, int iHeight);
	virtual void OnDisplayBackBuffer();

	// Key define
	int KEY_TERMINATE;
	static const int KEY_ESCAPE;
	static const int KEY_LEFT_ARROW;
	static const int KEY_RIGHT_ARROW;
	static const int KEY_UP_ARROW;
	static const int KEY_DOWN_ARROW;
	static const unsigned char KEY_W;
	static const unsigned char KEY_A;
	static const unsigned char KEY_S;
	static const unsigned char KEY_D;
	static const unsigned char KEY_Q;
	static const unsigned char KEY_E;
	// upper case
	static const unsigned char KEY_Wu;
	static const unsigned char KEY_Au;
	static const unsigned char KEY_Su;
	static const unsigned char KEY_Du;
	static const unsigned char KEY_Qu;
	static const unsigned char KEY_Eu;

    // mouse buttons
    static const int MOUSE_LEFT_BUTTON;
    static const int MOUSE_MIDDLE_BUTTON;
    static const int MOUSE_RIGHT_BUTTON;

    // mouse state
    static const int MOUSE_UP;
    static const int MOUSE_DOWN;

    // mouse modifiers
    static const int MODIFIER_CONTROL;
    static const int MODIFIER_LBUTTON;
    static const int MODIFIER_MBUTTON;
    static const int MODIFIER_RBUTTON;
    static const int MODIFIER_SHIFT;

	// performance measurements
	void ResetTime();
	void MeasureTime();
	void UpdateFrameCount();
	void FrameRateControl(int iFrameRate);
	void DrawFrameRate(int iX, int iY, const ColorRGBA& rkColor);
	double m_dLastTime, m_dAccumulatedTime, m_dFrameRate;
	int m_iFrameCount, m_iAccumulatedFrameCount, m_iTimer, m_iMaxTimer;

protected:
	// constructor inputs
	const tCHAR* m_acWindowTitle;
	int m_iXPosition, m_iYPosition, m_iWidth, m_iHeight;
	
	int m_iWindowID;

    // The frame buffer parameters for the renderer creation.  You may set
    // these to values different than the defaults during your application
    // constructor call.
    FrameBuffer::FormatType m_eFormat;
    FrameBuffer::DepthType m_eDepth;
    FrameBuffer::StencilType m_eStencil;
    FrameBuffer::BufferingType m_eBuffering;
    FrameBuffer::MultisamplingType m_eMultisampling;

	// the OpenGL renderer
	Renderer* m_pkWglRenderer;

	// camera motion
	void InitializeCameraMotion(float fTrnSpeed, float fRotSpeed,
		float fTrnSpeedFactor = 2.0f, float fRotSpeedFactor = 2.0f);
	virtual bool MoveCamera();
	virtual void MoveForward ();
	virtual void MoveBackward ();
	virtual void MoveLeft ();
	virtual void MoveRight ();
	virtual void TurnLeft ();
	virtual void TurnRight ();

	CameraPtr m_spkCamera;
	Vector3f m_akAxisInWorld[3]; // in order [r, u, d]
	float m_fTrnSpeed, m_fRotSpeed;
	float m_fTrnSpeedFactor, m_fRotSpeedFactor;
	bool m_bCameraMoveable;
	bool m_bUArrowPressed;
	bool m_bDArrowPressed;
	bool m_bLArrowPressed;
	bool m_bRArrowPressed;
	bool m_bTLArrowPressed;
	bool m_bTRArrowPressed;

	// Object motion
	void InitializeObjectMotion(Spatial* pkMotionObject);
	bool MoveObject();
	void RotateTrackBall(float fX0, float fY0, float fX1, float fY1);
	SpatialPtr m_spkMotionObject;
	int m_iDoRoll, m_iDoYaw, m_iDoPitch;
    float m_fXTrack0, m_fYTrack0, m_fXTrack1, m_fYTrack1;
    Matrix3f m_kSaveRotate;
    bool m_bUseTrackBall, m_bTrackBallDown;

	// rotate camera
	Vector3f m_kSaveLocation, m_kSaveRVector;
	float m_fSaveDistance;
	float m_fMouseX0, m_fMouseY0, m_fMouseX1, m_fMouseY1;
	float m_fCamAngleX, m_fCamAngleY;
	float m_fNewCamAngleX, m_fNewCamAngleY;

};

#include "Rp2WindowApplication.inl"

}

#endif